﻿/*
 * 作者：新生命开发团队（http://www.newlifex.com/）
 * 
 * 版权：版权所有 (C) 新生命开发团队 2002-2014
*/

using System;
using System.Collections;
using System.Reflection;
using System.Xml.Serialization;
using CuteAnt.Reflection;

namespace CuteAnt.Messaging
{
	/// <summary>远程方法调用消息</summary>
	/// <remarks>
	/// 根据方法名<see cref="Name"/>在类型<see cref="Type"/>中找到方法，如果有多个签名，还得根据参数数组<see cref="Parameters"/>来选择。
	/// 仅支持无返回或单一返回，不支持out/ref等参数。
	///
	/// 在服务端，通过调用消息的<see cref="Invoke"/>方法执行调用。
	/// 如有异常，返回异常消息；
	/// 如返回空，返回空消息；
	/// 否则返回实体消息<see cref="EntityMessage"/>
	/// </remarks>
	public class MethodMessage : Message
	{
		#region -- 属性 --

		/// <summary>消息类型</summary>
		[XmlIgnore]
		public override MessageKind Kind
		{
			get { return MessageKind.Method; }
		}

		[NonSerialized]
		private Type _Type;

		/// <summary>实体类型。可以是接口或抽象类型（要求对象容器能识别）</summary>
		[XmlIgnore]
		public Type Type
		{
			get
			{
				if (_Type == null && !_TypeName.IsNullOrWhiteSpace())
				{
					_Type = _TypeName.GetTypeEx();
				}
				return _Type;
			}
			set
			{
				_Type = value;
				if (value != null)
				{
					_TypeName = value.FullName;
				}
				else
				{
					_TypeName = null;
				}
			}
		}

		private String _TypeName;

		/// <summary>实体类型名。可以是接口或抽象类型（要求对象容器能识别）</summary>
		public String TypeName
		{
			get { return _TypeName; }
			set { _TypeName = value; }
		}

		private String _Name;

		/// <summary>方法名</summary>
		public String Name
		{
			get { return _Name; }
			set { _Name = value; }
		}

		private Object[] _Parameters;

		/// <summary>参数数组</summary>
		public Object[] Parameters
		{
			get { return _Parameters; }
			set { _Parameters = value; }
		}

		[NonSerialized]
		private MethodInfo _Method;

		/// <summary>方法对象</summary>
		[XmlIgnore]
		public MethodInfo Method
		{
			get
			{
				if (_Method == null && Type != null && !Name.IsNullOrWhiteSpace())
				{
					// 静态、公共、非公共
					//_Method = Type.GetMethod(Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					//_Method = TypeX.GetMethod(Type, Name, TypeX.GetTypeArray(Parameters));
					_Method = Type.GetMethodEx(Name, Parameters.GetTypeArray());
				}
				return _Method;
			}
			set
			{
				_Method = value;
				if (value != null)
				{
					Type = value.DeclaringType;
					Name = value.Name;
				}
			}
		}

		#endregion

		#region -- 客户端 --

		//public static Object Invoke(MethodInfo method, params Object[] ps)
		//{
		//    return new MethodMessage() { Method = method, Parameters = ps }.Invoke();
		//}
		//public static Object Invoke(Type type, String name, params Object[] ps)
		//{
		//    return new MethodMessage() { Type = type, Name = name, Parameters = ps }.Invoke();
		//}

		/// <summary>根据包括类型和方法名的完整方法名，以及参数，创建方法消息</summary>
		/// <param name="fullMethodName">完整方法名</param>
		/// <param name="ps"></param>
		/// <returns></returns>
		public static MethodMessage Create(String fullMethodName, params Object[] ps)
		{
			if (fullMethodName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("fullMethodName");
			}
			Int32 p = fullMethodName.LastIndexOf(".");
			if (p <= 0 || p == fullMethodName.Length - 1)
			{
				throw new ArgumentOutOfRangeException("fullMethodName", "完整方法名中未找到类型名！");
			}
			var msg = new MethodMessage();
			msg.TypeName = fullMethodName.Substring(0, p);
			msg.Name = fullMethodName.Substring(p + 1);
			msg.Parameters = ps;
			return msg;
		}

		#endregion

		#region -- 服务端 --

		/// <summary>处理消息</summary>
		/// <returns></returns>
		public Message Invoke()
		{
			var method = Method;

			try
			{
				if (method == null)
				{
					throw new ArgumentNullException("Method", String.Format("无法找到目标方法{0}.{1}！", Type, Name));
				}
				//var rs = MethodInfoX.Create(method).Invoke(null, Parameters);
				var rs = "".Invoke(method, Parameters);
				if (rs == null)
				{
					return new NullMessage();
				}
				else if (rs is IList)
				{
					// 采用实体集合消息返回列表型数据，避免序列化反序列化实体集合所带来的各种问题，到了客户端后，一律转化为List<T>
					return new EntitiesMessage() { Values = rs as IList };
				}
				else
				{
					return new EntityMessage() { Value = rs };
				}
			}
			catch (Exception ex)
			{
				return new ExceptionMessage() { Value = ex };
			}
		}

		#endregion

		#region -- 辅助 --

		/// <summary>已重载。</summary>
		/// <returns></returns>
		public override String ToString()
		{
			return String.Format("{0} {1}.{2}", base.ToString(), TypeName, Name);
		}

		#endregion
	}
}